import json
import uuid
import random
from Cryptodome.Cipher import AES
from Cryptodome import Random
from prg.entity.config_entity import *
from prg.entity.authority_entity import *
import base64


class CommonBase:

    @staticmethod
    def get_types():
        base_type = {int, float, bool, complex, str, type(None)}
        list_type = {list, tuple, set}
        dict_type = {dict}
        return base_type, list_type, dict_type

    # 多级对象转字典
    @staticmethod
    def entity_to_dict(obj):
        base_type, list_type, dict_type = CommonBase.get_types()
        if type(obj) in dict_type:
            obj_rtn = {k: CommonBase.entity_to_dict(v) for k, v in obj.items()}
        elif type(obj) in list_type:
            obj_rtn = [CommonBase.entity_to_dict(v) for v in obj]
        elif type(obj) in base_type:
            obj_rtn = obj
        else:
            dict_val = {}
            dict_val.update(obj.__dict__)
            obj_rtn = CommonBase.entity_to_dict(dict_val)
        return obj_rtn

    # 字典转对象
    @staticmethod
    def dict_to_entity(dict_item, en=None):
        if en is None:
            obj_name = "obj_" + str(uuid.uuid1().int)
            exec("class " + obj_name + ": pass")
            target = eval(obj_name + "()")
        else:
            obj_name = en.__class__.__name__
            target = en
        base_type, list_type, dict_type = CommonBase.get_types()
        for key, val in dict_item.items():
            if not hasattr(target, key):
                exec(obj_name + "." + key + "=None")
            obj_val = getattr(target, key)
            if type(val) in dict_type and type(obj_val) in dict_type:
                rtn = val
            elif type(val) in dict_type:
                rtn = CommonBase.dict_to_entity(dict_item=val, en=obj_val)
            elif type(val) in list_type:
                rtn = [CommonBase.dict_to_entity(dict_item=item, en=eval(obj_val.__class__.__name__ + "()")) for item in val]
            else:
                rtn = val
            setattr(target, key, rtn)
        return target

    @staticmethod
    def entity_to_json(obj):
        dict_item = CommonBase.entity_to_dict(obj)
        json_str = json.dumps(dict_item)
        return json_str

    @staticmethod
    def json_to_entity(json_str, en=None):
        dict_item = json.loads(json_str)
        obj = CommonBase.dict_to_entity(dict_item=dict_item, en=en)
        return obj

    # 加密
    @staticmethod
    def aes_encryption(key, data, encoding="utf-8"):
        iv = Random.new().read(AES.block_size)
        bytes_key = key.encode(encoding)
        my_cipher = AES.new(bytes_key, AES.MODE_CFB, iv)
        my_decrypt = iv + my_cipher.encrypt(data.encode(encoding))
        base64_val = base64.b64encode(my_decrypt)
        return str(base64_val, encoding)

    # 解密
    @staticmethod
    def aes_decrypt(key, data, encoding="utf-8"):
        bytes_key = key.encode(encoding)
        data_text = base64.b64decode(bytes(data, encoding))
        iv = data_text[:16]
        data_val = data_text[16:]
        my_decrypt = AES.new(bytes_key, AES.MODE_CFB, iv)
        decrypt_text = my_decrypt.decrypt(data_val)
        return decrypt_text.decode(encoding)

    @staticmethod
    def aes_encryption_json(key, entity, encoding="utf-8"):
        json_str = CommonBase.entity_to_json(entity)
        encryption_str = CommonBase.aes_encryption(key, json_str, encoding)
        return encryption_str

    @staticmethod
    def aes_decrypt_json(key, data, en=None, encoding="utf-8"):
        json_str = CommonBase.aes_decrypt(key, data, encoding)
        entity = CommonBase.json_to_entity(json_str=json_str, en=en)
        return entity

    @staticmethod
    def random_code(size=8):
        random_str = ""
        while len(random_str) < size:
            random_str += random.choice("abcdefghijklmmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
        return random_str

    # 加密 key密钥 data数据 fq加密次数
    @staticmethod
    def xor_encryption(key, data, encode="utf-8", fq=0):
        key_bytes = key if type(key) == bytes else key.encode(encode)
        data_bytes = data if type(data) == bytes else data.encode(encode)
        key_num = 0
        bytes_len = len(data_bytes)
        key_len = len(key_bytes)
        for key_item in key_bytes:
            key_num += key_item
        data_index = key_num % bytes_len
        rtn = bytes([data_bytes[(i + data_index) % bytes_len] ^ key_bytes[i % key_len] for i in range(0, bytes_len)])
        if fq > 0:
            rtn = CommonBase.xor_encryption(key=key, data=rtn, fq=fq-1)
        return rtn

    # 解密 key密钥 data数据 fq加密次数
    @staticmethod
    def xor_decrypt(key, data, encode="utf-8", fq=0):
        key_bytes = key if type(key) == bytes else key.encode(encode)
        data_bytes = data if type(data) == bytes else data.encode(encode)
        key_num = 0
        bytes_len = len(data_bytes)
        key_len = len(key_bytes)
        for key_item in key_bytes:
            key_num += key_item
        data_index = bytes_len - key_num % bytes_len
        data_all = bytes([data_bytes[i] ^ key_bytes[i % key_len] for i in range(0, bytes_len)])
        rtn = data_all[data_index:] + data_all[0:data_index]
        if fq > 0:
            rtn = CommonBase.xor_decrypt(key=key, data=rtn, fq=fq-1)
        return rtn

